package cn.com.yusys.yusp.admin.security;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.data.repository.query.SecurityEvaluationContextExtension;

import cn.com.yusys.yusp.uaa.config.UaaConstants;
import cn.com.yusys.yusp.uaa.security.common.AuthoritiesConstants;
import cn.com.yusys.yusp.uaa.service.UaaDomainUserDetailService;

/**
 * UAA Web Security配置
 *
 * @since 1.0.0
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, proxyTargetClass = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    
    private final AuthenticationManagerBuilder authenticationManagerBuilder;

    @Autowired
    private UaaDomainUserDetailService userDetailService;

    /**
     * AuthProvider全限定名
     */
    @Value("${uaa.auth.provider-class:cn.com.yusys.yusp.admin.sso.SSOSecurityDaoAuthenticationProvider}")
    private String uaaAuthProviderClass;

//    @Value("${uaa.auth.provider-class:cn.com.yusys.yusp.uaa.security.SecurityDaoAuthenticationProvider}")
//    private String uaaAuthProviderClass;

    public WebSecurityConfiguration(AuthenticationManagerBuilder authenticationManagerBuilder) {
        this.authenticationManagerBuilder = authenticationManagerBuilder;
    }
    
    @Value("${use-uaa-user-service:true}")
    public String useUaaUserService;

    @PostConstruct
    public void init() throws Exception {
        authenticationManagerBuilder
                .authenticationProvider(securityDaoAuthenticationProvider());
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public DaoAuthenticationProvider securityDaoAuthenticationProvider() throws Exception {

        DaoAuthenticationProvider authProvider = (DaoAuthenticationProvider) Class.forName(this.uaaAuthProviderClass).newInstance();
        authProvider.setPasswordEncoder(passwordEncoder());
        if (UaaConstants.UAA_AUTH_PROVIDER_CLASS.equalsIgnoreCase(uaaAuthProviderClass) || "true".equalsIgnoreCase(useUaaUserService)) {
            // 使用默认的与本地数据库绑定的user details service
            authProvider.setUserDetailsService(userDetailService);
        } else {
            // 用户使用第三方用户校验服务
            authProvider.setUserDetailsService(username -> {
                List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
                grantedAuthorities.add(new SimpleGrantedAuthority(AuthoritiesConstants.ADMIN));
                return new User(username, username, grantedAuthorities);
            });
        }
        return authProvider;
    }

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    public void configure(WebSecurity web) {
        web.ignoring()
                .antMatchers(HttpMethod.OPTIONS, "/**")
                .antMatchers("/app/**/*.{js,html}")
                .antMatchers("/bower_components/**")
                .antMatchers("/i18n/**")
                .antMatchers("/content/**")
                // 由于在管控平台中查看每个服务的SwaggerAPI接口文档时，会先通过网关到UAA获取一个OAuth Token，然后使用这个Token再访问各个服务的/v2/api-docs接口,现在UAA只管Toke生成，不做Token校验，因此，访问UAA的/v2/api-docs接口携带的OAuth Token将无法校验。
                .antMatchers("/v2/api-docs/**")
                .antMatchers("/swagger-ui/index.html")
                .antMatchers("/test/**")
                .antMatchers("/h2-console/**");
    }

    @Bean
    public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
        return new SecurityEvaluationContextExtension();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.logout();
    }
}
